package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.redis.RedisOfLearningRecord;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;

import static com.tianji.learning.enums.LessonStatus.FINISHED;
import static com.tianji.learning.enums.SectionType.EXAM;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author WFan
 * @since 2025-03-24
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {
    private final ILearningLessonService learningLessonService;
    private final RedisOfLearningRecord redisOfLearningRecord;

    /**
     * 查询用户指定课程的学习进度
     *
     * @param courseId
     * @return
     */
    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {
        // 1.查询课表信息，获得最近学习的小节id
        LearningLesson lesson = learningLessonService.lambdaQuery().eq(LearningLesson::getCourseId, courseId)
                .eq(LearningLesson::getUserId, UserContext.getUser())
                .one();
        if (ObjectUtil.isEmpty(lesson)) {
            log.warn("未查询到该学习课程");
            return null;
        }

        // 2.查询学习记录表获取该课表下的学习记录
        List<LearningRecord> learningRecordList = this.lambdaQuery().eq(LearningRecord::getLessonId, lesson.getId()).list();

        return LearningLessonDTO.of(lesson.getId(), lesson.getLatestSectionId(), BeanUtil.copyToList(learningRecordList, LearningRecordDTO.class));

    }

    /**
     * 提交学习记录
     *
     * @param learningRecordFormDTO
     */
    @Override
    public void submitLearningRecord(LearningRecordFormDTO learningRecordFormDTO) {
        // 第一次完成小节学习标记
        Boolean finished = false;

        // 课程全部学完标记
        Boolean finishAll = false;

        // 1.判断是否是考试
        if (learningRecordFormDTO.getSectionType().equals(EXAM)) {
            handleExamRecord(learningRecordFormDTO);
            finished = true;
        } else {
            finished = handleVideoRecord(learningRecordFormDTO, finished);
        }

        // 4.如果是否学完全部小节
        // 4.1 查询完成的小节数量
        Integer count = this.lambdaQuery().eq(LearningRecord::getLessonId, learningRecordFormDTO.getLessonId())
                .eq(LearningRecord::getFinished, true)
                .count();
        // 4.2 查询小节总数
        Integer total = learningLessonService.lambdaQuery().eq(LearningLesson::getId, learningRecordFormDTO.getLessonId())
                .eq(LearningLesson::getUserId, UserContext.getUser())
                .count();

        if (finished) {
            finishAll = (count + 1) >= total;
        }

        // 5.更新课表信息
        learningLessonService.lambdaUpdate().eq(LearningLesson::getId, learningRecordFormDTO.getLessonId())
                .set(LearningLesson::getLatestSectionId, learningRecordFormDTO.getSectionId())
                .set(finishAll, LearningLesson::getStatus, FINISHED)
                .set(finished, LearningLesson::getLearnedSections, count + 1)
                .update();
    }

    /**
     * 处理考试记录
     * @param learningRecordFormDTO
     */
    private void handleExamRecord(LearningRecordFormDTO learningRecordFormDTO) {
        LearningRecord newRecord = BeanUtil.toBean(learningRecordFormDTO, LearningRecord.class);
        newRecord.setFinished(true);
        newRecord.setUserId(UserContext.getUser());
        this.save(newRecord);
    }

    /**
     * 处理视频记录
     * @param learningRecordFormDTO
     * @param finished
     * @return
     */
    private Boolean handleVideoRecord(LearningRecordFormDTO learningRecordFormDTO, Boolean finished) {
        // 1.从Redis中查询当前小节学习记录是否存在
        LearningRecord record = redisOfLearningRecord.readLearningRecordFromCache(learningRecordFormDTO.getLessonId(), learningRecordFormDTO.getSectionId());
        if (ObjectUtil.isEmpty(record)){
            // 1.1缓存中没有学习记录，则从数据库查询
            record = this.lambdaQuery().eq(LearningRecord::getLessonId, learningRecordFormDTO.getLessonId())
                    .eq(LearningRecord::getSectionId, learningRecordFormDTO.getSectionId())
                    .one();
            if (ObjectUtil.isNotNull(record)){
                // 1.2数据库有记录则缓存学习小节
                redisOfLearningRecord.saveLearningRecordToCache(record);
            }
        }

        //  2.判断学习记录是否存在
        if (ObjectUtil.isEmpty(record)) {
            // 2.1不存在学习记录，则新增学习记录
            LearningRecord newRecord = BeanUtil.toBean(learningRecordFormDTO, LearningRecord.class);
            newRecord.setFinished(false);
            newRecord.setUserId(UserContext.getUser());
            this.save(newRecord);
        } else {
            // 2.2存在学习记录，则走更新逻辑
            // 判断是否第一次学完
            finished = !record.getFinished() && learningRecordFormDTO.getMoment() << 1 >= learningRecordFormDTO.getDuration();
            if (finished) {
                // 学完小节则更新学习记录
                record.setMoment(learningRecordFormDTO.getMoment());
                this.lambdaUpdate().eq(LearningRecord::getId, record.getId())
                        .set(LearningRecord::getMoment, learningRecordFormDTO.getMoment())
                        .set(finished, LearningRecord::getFinished, finished)
                        .update();
                // 删除缓存
                redisOfLearningRecord.deleteLearningRecordFromCache(learningRecordFormDTO.getLessonId(), learningRecordFormDTO.getSectionId());
            }else {
                // 小节未学完，将数据更新至缓,提交延时任务
                redisOfLearningRecord.submitDelayTask(learningRecordFormDTO);
            }
        }
        return finished;
    }
}
